﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace PhantomMvvmToolkit.Control
{
    public partial class Repeater
    {
        // This property will allow the control to know when the data context changes at runtime
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource",
                                        typeof(IEnumerable),
                                        typeof(Repeater),
                                        new PropertyMetadata(null, SetItemsSource));

        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register("ItemTemplate",
                                        typeof(DataTemplate),
                                        typeof(Repeater),
                                        new PropertyMetadata(null, SetItemTemplate));

        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation",
                                        typeof(Orientation),
                                        typeof(Repeater),
                                        new PropertyMetadata(Orientation.Vertical, SetOrientation));

        private static void SetItemsSource(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var casted = d as Repeater;
            if (casted != null)
                casted.ItemsSource = e.NewValue as IEnumerable;
        }

        private static void SetItemTemplate(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var casted = d as Repeater;
            if (casted != null)
                casted.ItemTemplate = e.NewValue as DataTemplate;
        }

        private static void SetOrientation(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var casted = d as Repeater;
            if (casted != null && e.NewValue is Orientation)
                casted.Orientation = (Orientation)e.NewValue;
        }

        public Repeater()
        {
            InitializeComponent();
        }

        private IEnumerable _itemsSource;
        public IEnumerable ItemsSource
        {
            get { return _itemsSource; }
            set
            {
                var source = ItemsSource as INotifyCollectionChanged;
                if (source != null)
                {
                    source.CollectionChanged -= ItemsSourceCollectionChanged;
                }

                _itemsSource = value;

                source = ItemsSource as INotifyCollectionChanged;
                if (source != null)
                {
                    source.CollectionChanged += ItemsSourceCollectionChanged;
                }

                RebuildChildren();
            }
        }

        private DataTemplate _itemTemplate;
        public DataTemplate ItemTemplate
        {
            get { return _itemTemplate; } 
            set
            {
                _itemTemplate = value;

                if (ItemsSource != null)
                {
                    RebuildChildren();
                }
            }
        }

        public Orientation Orientation
        {
            get { return UxStackPanel.Orientation; }
            set { UxStackPanel.Orientation = value; }
        }

        private void RebuildChildren()
        {
            UxStackPanel.Children.Clear();

            if (ItemsSource != null)
            {
                foreach (var item in ItemsSource)
                {
                    var newItem = BuildNewItem(item);
                    UxStackPanel.Children.Add(newItem);
                }
            }
        }

        private UIElement BuildNewItem(object dataSource)
        {
            var newItem = (FrameworkElement)null;

            if (ItemTemplate != null)
                newItem = ItemTemplate.LoadContent() as FrameworkElement;

            if (newItem == null)
            {
                newItem = new TextBlock();
                newItem.SetBinding(TextBlock.TextProperty, new Binding());
            }

            newItem.DataContext = dataSource;

            return newItem;
        }

        private void ItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Replace:

                    if (e.OldItems != null)
                    {
                        foreach (var o in e.OldItems)
                        {
                            var item = UxStackPanel.Children.Cast<FrameworkElement>().FirstOrDefault(x => x.DataContext == o);

                            if (item != null)
                                UxStackPanel.Children.Remove(item);
                        }
                    }

                    if (e.NewItems != null)
                    {
                        var newIndexOffset = e.NewStartingIndex;

                        foreach (var n in e.NewItems)
                        {
                            UxStackPanel.Children.Insert(newIndexOffset++, BuildNewItem(n));
                        }

                        //if (e.NewStartingIndex == UxStackPanel.Children.Count)
                        //{
                        //    foreach (var n in e.NewItems)
                        //    {
                        //        UxStackPanel.Children.Add(BuildNewItem(n));
                        //    }
                        //}
                        //else
                        //{
                            
                        //}
                    }

                    break;
                case NotifyCollectionChangedAction.Reset:
                    RebuildChildren();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }
}
